#include <engine.h>

float InvSqrt(float x)
{
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i >> 1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    return x;
}


cBaseAnimation::cBaseAnimation()
{
//    printf("Default constructor\n");
    m_bActive = 0;
    m_nCounter = 0;
    m_nFrameCounter = 0;
    m_nLastState = 0;
    m_nRepeat = 0;
}

cBaseAnimation::cBaseAnimation(GrafixObjectStack * pWs, int x, int y)
{
//    m_pWs = animationmanager;
//    m_cLayerManager = &m_pWs->m_cLayerManger;
//    m_bSkipMsg = false;
//    printf("NULL up\n");
}

cBaseAnimation::~cBaseAnimation()
{
//    printf("NULL down\n");
}

int cBaseAnimation::SetAnimationParam(int param1, int param2, int param3, int param4)
{
    return 0;
}

int cBaseAnimation::Destroy()
{
    m_pWs->InternalDeleteAnime(m_nAnimationId);
    return 0;
}

int cBaseAnimation::Start()
{
    m_bActive = 1;
    return 0;
}

int cBaseAnimation::Stop()
{
    m_bActive = 0;
    return 0;
}


int cBaseAnimation::UpdateAnimation()
{
    return 0;
}

int cBaseAnimation::Reset()
{
    return 0;
}

int cBaseAnimation::ForceRender()
{
    return 0;
}

int cBaseAnimation::OnMouseMove(int x, int y)
{
    return 0;
}

int cBaseAnimation::OnMouseDown(int x, int y)
{
    return 0;
}

int cBaseAnimation::OnMouseUp(int x, int y)
{
    return 0;
}

int cBaseAnimation::OnKeyDown(unsigned int param1)
{
    return 0;
}

int cBaseAnimation::OnKeyUp(unsigned int param1)
{
    return 0;
}


int cBaseAnimation::AutoSleep(int counter)
{
    if (counter == m_nLastState)
        m_nCounter++;
    else {
        m_nLastState = counter;
        m_nCounter = 0;
    }

    if (m_nCounter>80)
        m_bActive = 0;

    return 0;
}

int cBaseAnimation::AutoSleep0(int counter)
{
    if (counter == 0)
        m_nCounter++;
    else {
        m_nCounter = 0;
    }

    if (m_nCounter>80)
        m_bActive = 0;

    return 0;
}


cMoveAction::cMoveAction(int OffsetX, int OffsetY,
                         GrafixObjectStack * pWs, LayerManagerEX * pLM,
                         int * pGroup, int num, int style, int BeginFrame, int duration,
                         ANICALLBACK fpAnime, void * pAnime, int gid)
{
    m_nGid = gid;
    m_pLM = pLM;
    m_pLM->SelectGroup(m_nGid);
    m_fpAniCallBack = fpAnime;
    m_pAniClass = pAnime;
    m_nStyle = style;
    m_pWs = pWs;
    m_nX1 = m_pLM->GetLayerPosition(pGroup[0])->x;
    m_nY1 = m_pLM->GetLayerPosition(pGroup[0])->y;
    m_nX2 = m_nX1+OffsetX;
    m_nY2 = m_nY1+OffsetY;

    m_nLayerNum = num;

    if (pGroup) {
        m_pGroup = new GROUPUNIT[num];
        m_pGroup[0].nId = pGroup[0];
        m_pGroup[0].nOffset1 = 0;
        m_pGroup[0].nOffset2 = 0;

        for (int i=1; i<num; i++) {
            m_pGroup[i].nId = pGroup[i];
            m_pGroup[i].nOffset1 = (m_pLM->GetLayerPosition(pGroup[i])->x)
                                 - (m_pLM->GetLayerPosition(pGroup[0])->x);
            m_pGroup[i].nOffset2 = (m_pLM->GetLayerPosition(pGroup[i])->y)
                                 - (m_pLM->GetLayerPosition(pGroup[0])->y);
        }
    }
    else {
       int* lid=0;
       m_nLayerNum = pLM->GetNumberOfLayers();
       lid = new int[m_nLayerNum];
       m_nLayerNum = pLM->GetAllLayerIds(lid);
       m_pGroup = new GROUPUNIT[m_nLayerNum];
       for (int i=0; i<m_nLayerNum; i++) {
          m_pGroup[i].nId = lid[i];
          m_pGroup[i].nOffset1 = (m_pLM->GetLayerPosition(pGroup[i])->x)
                               - (m_pLM->GetLayerPosition(pGroup[0])->x);
          m_pGroup[i].nOffset2 = (m_pLM->GetLayerPosition(pGroup[i])->y)
                               - (m_pLM->GetLayerPosition(pGroup[0])->y);
       }
       if (lid) delete lid;
    }

    m_nDuration = duration;

    m_nDX = m_nX2 - m_nX1;
    m_nDY = m_nY2 - m_nY1;

    m_nBeginFrame = BeginFrame;
    m_nFrameCounter = 0;
    m_nElapsedTime = 0;

    if (abs(m_nDX)>abs(m_nDY)) {
        m_nHVmode = 0;
    }
    else {
        m_nHVmode = 1;
    }

    if (m_nDX == 0 && m_nDY == 0) {
        m_nDX = 1;
        m_nDY = 1;
        m_bActive = 0;
    }
    else m_bActive = 1;


}

cMoveAction::cMoveAction(int SrcX, int SrcY, int DstX, int DstY,
                         GrafixObjectStack * pWs, LayerManagerEX * pLM,
                         int * pGroup, int num, int style, int BeginFrame, int duration,
                         ANICALLBACK fpAnime, void * pAnime, int gid)
{
    m_nGid = gid;
    m_pLM = pLM;
    m_pLM->SelectGroup(m_nGid);
    m_fpAniCallBack = fpAnime;
    m_pAniClass = pAnime;
    m_nStyle = style;
    m_pWs = pWs;
    m_nX1 = SrcX;
    m_nY1 = SrcY;
    m_nX2 = DstX;
    m_nY2 = DstY;

    m_nLayerNum = num;

    if (pGroup) {
        m_pGroup = new GROUPUNIT[num];
        m_pGroup[0].nId = pGroup[0];
        m_pGroup[0].nOffset1 = 0;
        m_pGroup[0].nOffset2 = 0;

        for (int i=1; i<num; i++) {
            m_pGroup[i].nId = pGroup[i];
            m_pGroup[i].nOffset1 = (m_pLM->GetLayerPosition(pGroup[i])->x)
                                 - (m_pLM->GetLayerPosition(pGroup[0])->x);
            m_pGroup[i].nOffset2 = (m_pLM->GetLayerPosition(pGroup[i])->y)
                                 - (m_pLM->GetLayerPosition(pGroup[0])->y);
        }
    }
    else {
       int* lid=0;
       m_nLayerNum = pLM->GetNumberOfLayers();
       lid = new int[m_nLayerNum];
       m_nLayerNum = pLM->GetAllLayerIds(lid);
       m_pGroup = new GROUPUNIT[m_nLayerNum];
       for (int i=0; i<m_nLayerNum; i++) {
          m_pGroup[i].nId = lid[i];
          m_pGroup[i].nOffset1 = (m_pLM->GetLayerPosition(pGroup[i])->x)
                               - (m_pLM->GetLayerPosition(pGroup[0])->x);
          m_pGroup[i].nOffset2 = (m_pLM->GetLayerPosition(pGroup[i])->y)
                               - (m_pLM->GetLayerPosition(pGroup[0])->y);
       }
       if (lid) delete lid;
    }

    m_nGid = gid;
    m_nDuration = duration;

    m_nDX = m_nX2 - m_nX1;
    m_nDY = m_nY2 - m_nY1;

    m_nBeginFrame = BeginFrame;
    m_nFrameCounter = 0;
    m_nElapsedTime = 0;

    if (abs(m_nDX)>abs(m_nDY)) {
        m_nHVmode = 0;
    }
    else {
        m_nHVmode = 1;
    }

    if (m_nDX == 0 && m_nDY == 0) {
        m_nDX = 1;
        m_nDY = 1;
        m_bActive = 0;
    }
    else m_bActive = 1;


}


cMoveAction::~cMoveAction()
{
    if (m_pGroup)
        delete m_pGroup;
}


int cMoveAction::SetAnimationParam(int param1, int param2, int param3, int param4)
{
    return 0;
}

int cMoveAction::OnFinish()
{
//    m_bActive = 0;
//    printf("delete %d\n",m_nAnimationId);
    for (int i=0; i<m_nLayerNum; i++) {
        m_pLM->SetLayerPosition(m_pGroup[i].nId,
                                m_pGroup[i].nOffset1+m_nX2,
                                m_pGroup[i].nOffset2+m_nY2);
    }
    if (m_fpAniCallBack)
        m_fpAniCallBack(m_pAniClass);
    m_pWs->InternalDeleteAnime(m_nAnimationId);
    return 0;
}

int cMoveAction::UpdateAnimation()
{
    int i;
    if (m_nElapsedTime<m_nBeginFrame) m_nElapsedTime++;
    else {
        m_nFrameCounter++;
        m_pLM->SelectGroup(m_nGid);
        switch (m_nStyle & 3) {
            case 0:
                if (!m_nHVmode) {
                    m_nCurrX = m_nFrameCounter * m_nDX / m_nDuration;
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nFrameCounter * m_nDY / m_nDuration;
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->SetLayerPosition(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY);
                }
                break;
            case 1:

                if (!m_nHVmode) {
                    m_nCurrX = m_nFrameCounter * m_nFrameCounter * m_nDX
                             / (m_nDuration * m_nDuration);
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nFrameCounter * m_nFrameCounter * m_nDY
                             / (m_nDuration * m_nDuration);
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->SetLayerPosition(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY);
                }
                break;
            case 2:
                if (!m_nHVmode) {
                    m_nCurrX = m_nDX * ((m_nDuration<<1) - m_nFrameCounter)
                             * m_nFrameCounter / (m_nDuration*m_nDuration);
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nDY * ((m_nDuration<<1) - m_nFrameCounter)
                             * m_nFrameCounter / (m_nDuration*m_nDuration);
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->SetLayerPosition(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY);
                }
                break;
            case 3:
                if (!m_nHVmode) {

                    if (m_nFrameCounter<(m_nDuration>>1))
                        m_nCurrX = m_nFrameCounter * m_nFrameCounter * m_nDX
                                 /(m_nDuration * m_nDuration) * 2;
                    else
                        m_nCurrX = m_nDX * (4 * m_nFrameCounter * m_nDuration
                                 - m_nFrameCounter * m_nFrameCounter * 2
                                 - m_nDuration * m_nDuration)
                                 / (m_nDuration * m_nDuration);

                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    if (m_nFrameCounter<(m_nDuration>>1))
                        m_nCurrY = m_nFrameCounter * m_nFrameCounter * m_nDY
                                 / (m_nDuration * m_nDuration) * 2;
                    else
                        m_nCurrY = m_nDY * ( 4 * m_nFrameCounter * m_nDuration
                                 - m_nFrameCounter * m_nFrameCounter * 2
                                 - m_nDuration * m_nDuration)
                                 / (m_nDuration * m_nDuration);

                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->SetLayerPosition(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY);
                }
                break;
        }

        if (m_nFrameCounter>m_nDuration) OnFinish();
    }
    return 0;
}

int cMoveAction::Reset()
{
    return 0;
}

cFlashAction::cFlashAction(int value1, int value2,
                 GrafixObjectStack * pWs, LayerManagerEX * pLM,
                 int * pGroup, int num, int style, int times, int BeginFrame, int duration,
                 ANICALLBACK fpAnime, void * pAnime, int gid)
{
    m_nGid = gid;
    m_pLM = pLM;
    m_pLM->SelectGroup(m_nGid);
    m_fpAniCallBack = fpAnime;
    m_pAniClass = pAnime;
    m_nDirection = 1;
    m_pWs = pWs;
    m_nValue1 = value1;
    m_nValue2 = value2;

    m_nLayerNum = num;
    m_nGid = gid;

    if (pGroup) {
        m_pGroup = new GROUPUNIT[num];
        for (int i=0; i<num; i++) {
            m_pGroup[i].nId = pGroup[i];
            m_pGroup[i].nOffset1 = m_pLM->GetLayerTransparency(pGroup[i])
                                 - m_pLM->GetLayerTransparency(pGroup[0]);
        }
    }
    else {
        int* lid=0;
        m_nLayerNum = pLM->GetNumberOfLayers();
        lid = new int[m_nLayerNum];
        m_nLayerNum = pLM->GetAllLayerIds(lid);
        m_pGroup = new GROUPUNIT[m_nLayerNum];
        for (int i=0; i<m_nLayerNum; i++) {
            m_pGroup[i].nId = lid[i];
            m_pGroup[i].nOffset1 = m_pLM->GetLayerTransparency(pGroup[i])
                                 - m_pLM->GetLayerTransparency(pGroup[0]);
        }
        if (lid) delete lid;
    }

    m_nBeginFrame = BeginFrame;
    m_nFrameCounter = 0;
    m_nElapsedTime = 0;

    m_nStyle = style;
    m_nRepeat = times;
    m_nCurrent = value1;
    m_nDuration = duration;
    m_nDirection = 1;
    m_bActive = 1;
}


int cFlashAction::SetAnimationParam(int param1, int param2, int param3, int param4)
{
    m_nDirection = param1;
    return 0;
}

int cFlashAction::UpdateAnimation()
{
    int i;
    if (m_nElapsedTime<m_nBeginFrame) m_nElapsedTime++;
    else {
        m_pLM->SelectGroup(m_nGid);
        if (0 == m_nRepeat) {
            OnFinish();
            return 0;
        }

        m_nCurrent = m_nValue1 + m_nFrameCounter*(m_nValue2-m_nValue1)/m_nDuration;

        for (i=0; i<m_nLayerNum; i++) {
            m_pLM->SetLayerTransparency(m_pGroup[i].nId, m_nCurrent+m_pGroup[i].nOffset1);
        }

        m_nFrameCounter+=m_nDirection;

        if (m_nFrameCounter>m_nDuration) {
            if (!(m_nStyle&MIRROR)) {
                if (m_nRepeat != -1) m_nRepeat--;
                if (0==m_nRepeat) {
                    for (i=0; i<m_nLayerNum; i++) {
                        m_pLM->SetLayerTransparency(m_pGroup[i].nId, m_nValue2+m_pGroup[i].nOffset1);
                    }
                    return 0;
                }
                m_nCurrent = m_nValue1;
                m_nFrameCounter=0;
            }
            else if (m_nStyle&MIRROR) {
                m_nCurrent = m_nValue2;
                m_nDirection =-1;
            }
            for (i=0; i<m_nLayerNum; i++) {
                m_pLM->SetLayerTransparency(m_pGroup[i].nId, m_nValue2+m_pGroup[i].nOffset1);
            }
        }
        else if (m_nFrameCounter<0) {
            m_nCurrent = m_nValue1;
            m_nFrameCounter=0;
            m_nDirection = 1;
            for (i=0; i<m_nLayerNum; i++) {
                m_pLM->SetLayerTransparency(m_pGroup[i].nId, m_nValue1+m_pGroup[i].nOffset1);
            }
            if (m_nRepeat != -1) m_nRepeat--;
        }
    }

    return 0;
}

int cFlashAction::OnFinish()
{
//    m_bActive = 0;
//    printf("delete %d\n",m_nAnimationId);
    if (m_fpAniCallBack)
        m_fpAniCallBack(m_pAniClass);
    m_pWs->InternalDeleteAnime(m_nAnimationId);
    return 0;
}

int cFlashAction::Reset()
{
    return 0;
}

cFlashAction::~cFlashAction()
{
    if (m_pGroup)
        delete m_pGroup;
}

cStretchAction::cStretchAction(int SrcW, int SrcH, int DstW, int DstH,
                     GrafixObjectStack * pWs, LayerManagerEX * pLM,
                     int * pGroup, int num, int style, int times, int BeginFrame, int duration,
                     ANICALLBACK fpAnime, void * pAnime, int gid)
{
    m_nGid = gid;
    m_pLM = pLM;
    m_pLM->SelectGroup(m_nGid);
    m_fpAniCallBack = fpAnime;
    m_pAniClass = pAnime;
    m_nDirection = 1;
    m_pWs = pWs;
    m_nX1 = SrcW;
    m_nY1 = SrcH;
    m_nX2 = DstW;
    m_nY2 = DstH;

    m_nStyle = style;
    m_nRepeat = times;
    m_nFrameCounter = 0;
    m_nDuration = duration;
    m_nDirection = 1;
    m_nBeginFrame = BeginFrame;
    m_nFrameCounter = 0;
    m_nElapsedTime = 0;
    m_nLayerNum = num;

    if (pGroup) {
        m_pGroup = new GROUPUNIT[num];
        m_pGroup[0].nId = pGroup[0];
        m_pGroup[0].nOffset1 = 0;
        m_pGroup[0].nOffset2 = 0;
        for (int i=1; i<num; i++) {
            m_pGroup[i].nId = pGroup[i];
            m_pGroup[i].nOffset1 = m_pLM->GetLayerInfo(pGroup[i])->StretchInfo.Width
                                 - m_pLM->GetLayerInfo(pGroup[0])->StretchInfo.Width;
            m_pGroup[i].nOffset2 = m_pLM->GetLayerInfo(pGroup[i])->StretchInfo.Height
                                 - m_pLM->GetLayerInfo(pGroup[0])->StretchInfo.Height;
        }
    }
    else {
        int* lid=0;
        m_nLayerNum = pLM->GetNumberOfLayers();
        lid = new int[m_nLayerNum];
        m_nLayerNum = pLM->GetAllLayerIds(lid);
        m_pGroup = new GROUPUNIT[m_nLayerNum];
        for (int i=0; i<m_nLayerNum; i++) {
            m_pGroup[i].nId = lid[i];
            m_pGroup[i].nOffset1 = m_pLM->GetLayerInfo(pGroup[i])->StretchInfo.Width
                                 - m_pLM->GetLayerInfo(pGroup[0])->StretchInfo.Width;
            m_pGroup[i].nOffset2 = m_pLM->GetLayerInfo(pGroup[i])->StretchInfo.Height
                                 - m_pLM->GetLayerInfo(pGroup[0])->StretchInfo.Height;
        }
        if (lid) delete lid;
    }

    m_nDX = (m_nX2 - m_nX1);
    m_nDY = (m_nY2 - m_nY1);

    if (abs(m_nDX)>abs(m_nDY)) {
        m_nHVmode = 0;
    }
    else {
        m_nHVmode = 1;
    }

    m_bActive = 1;

}

int cStretchAction::ResizeLayer(int width, int height, int style)
{
    int i;
    for (i=0; i<m_nLayerNum; i++) {
        m_pLM->ResizeLayer(m_pGroup[i].nId, width, height,
                           (((style&0xC)>>2)+1)%3,
                           (((style&0x30)>>4)+1)%3);
    }
    return 0;
}


int cStretchAction::SetAnimationParam(int param1, int param2, int param3, int param4)
{
    return 0;
}

int cStretchAction::UpdateAnimation()
{
//    DebugBreak();
    int i;

    if (m_nElapsedTime<m_nBeginFrame) m_nElapsedTime++;
    else {
        m_pLM->SelectGroup(m_nGid);
        if (0 == m_nRepeat) {
            OnFinish();
            return 0;
        }


        switch (m_nStyle & 3) {
            case 0:
                if (!m_nHVmode) {
                    m_nCurrX = m_nFrameCounter * m_nDX / m_nDuration;
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nFrameCounter * m_nDY / m_nDuration;
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->ResizeLayer(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY,
                                            (((m_nStyle&0xC)>>2)+1)%3,
                                            (((m_nStyle&0x30)>>4)+1)%3);
                }
                break;
            case 1:

                if (!m_nHVmode) {
                    m_nCurrX = m_nFrameCounter * m_nFrameCounter * m_nDX
                             / (m_nDuration * m_nDuration);
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nFrameCounter * m_nFrameCounter * m_nDY
                             / (m_nDuration * m_nDuration);
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->ResizeLayer(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY,
                                            (((m_nStyle&0xC)>>2)+1)%3,
                                            (((m_nStyle&0x30)>>4)+1)%3);
                }
                break;
            case 2:
                if (!m_nHVmode) {
                    m_nCurrX = m_nDX * ((m_nDuration<<1) - m_nFrameCounter)
                             * m_nFrameCounter / (m_nDuration*m_nDuration);
                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    m_nCurrY = m_nDY * ((m_nDuration<<1) - m_nFrameCounter)
                             * m_nFrameCounter / (m_nDuration*m_nDuration);
                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->ResizeLayer(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY,
                                            (((m_nStyle&0xC)>>2)+1)%3,
                                            (((m_nStyle&0x30)>>4)+1)%3);
                }
                break;
            case 3:
                if (!m_nHVmode) {
                    if (m_nFrameCounter<(m_nDuration>>1))
                        m_nCurrX = m_nFrameCounter * m_nFrameCounter * m_nDX
                                 / (m_nDuration * m_nDuration) * 2;
                    else
                        m_nCurrX = m_nDX * (4 * m_nFrameCounter * m_nDuration
                                 - m_nFrameCounter * m_nFrameCounter * 2
                                 - m_nDuration * m_nDuration)
                                 / (m_nDuration * m_nDuration);

                    m_nCurrY = m_nCurrX * m_nDY / m_nDX;
                }
                else {
                    if (m_nFrameCounter<(m_nDuration>>1))
                        m_nCurrY = m_nFrameCounter * m_nFrameCounter * m_nDY
                                 / (m_nDuration * m_nDuration) * 2;
                    else
                        m_nCurrY = m_nDY * (4 * m_nFrameCounter * m_nDuration
                                 - m_nFrameCounter * m_nFrameCounter * 2
                                 - m_nDuration * m_nDuration)
                                 / (m_nDuration * m_nDuration);

                    m_nCurrX = m_nCurrY * m_nDX / m_nDY;
                }
                for (i=0; i<m_nLayerNum; i++) {
                    m_pLM->ResizeLayer(m_pGroup[i].nId,
                                            m_pGroup[i].nOffset1+m_nX1+m_nCurrX,
                                            m_pGroup[i].nOffset2+m_nY1+m_nCurrY,
                                            (((m_nStyle&0xC)>>2)+1)%3,
                                            (((m_nStyle&0x30)>>4)+1)%3);
                }
                break;
        }

        m_nFrameCounter+=m_nDirection;

        if (m_nFrameCounter>m_nDuration) {
            if (!(m_nStyle&MIRROR)) {
                if (m_nRepeat != -1) m_nRepeat--;
                if (0==m_nRepeat) {
                    for (i=0; i<m_nLayerNum; i++) {
                        m_pLM->ResizeLayer(m_pGroup[i].nId,
                                                m_pGroup[i].nOffset1+m_nX2,
                                                m_pGroup[i].nOffset2+m_nY2,
                                                (((m_nStyle&0xC)>>2)+1)%3,
                                                (((m_nStyle&0x30)>>4)+1)%3);
                    }
                    return 0;
                }
                m_nFrameCounter=0;
            }
            else if (m_nStyle&MIRROR) {
                m_nDirection =-1;
            }
            for (i=0; i<m_nLayerNum; i++) {
                m_pLM->ResizeLayer(m_pGroup[i].nId,
                                        m_pGroup[i].nOffset1+m_nX2,
                                        m_pGroup[i].nOffset2+m_nY2,
                                        (((m_nStyle&0xC)>>2)+1)%3,
                                        (((m_nStyle&0x30)>>4)+1)%3);
            }
        }
        else if (m_nFrameCounter<0) {
            m_nFrameCounter=0;
            m_nDirection = 1;
            if (m_nRepeat != -1) m_nRepeat--;
            for (i=0; i<m_nLayerNum; i++) {
                m_pLM->ResizeLayer(m_pGroup[i].nId,
                                        m_pGroup[i].nOffset1+m_nX1,
                                        m_pGroup[i].nOffset2+m_nY1,
                                        (((m_nStyle&0xC)>>2)+1)%3,
                                        (((m_nStyle&0x30)>>4)+1)%3);
            }
        }
    }

    return 0;
}

int cStretchAction::OnFinish()
{
//    m_bActive = 0;
//    printf("delete %d\n",m_nAnimationId);
    if (m_fpAniCallBack)
        m_fpAniCallBack(m_pAniClass);
    m_pWs->InternalDeleteAnime(m_nAnimationId);
    return 0;
}

int cStretchAction::Reset()
{
    return 0;
}

cStretchAction::~cStretchAction()
{
    if (m_pGroup)
        delete m_pGroup;
}

